/**
 *
 * @author Patricia Blanco created 2013 copyright 2013
 */
package dieci.database.product;

import dieci.database.PersistentObject;
import dieci.database.SessionFactoryUtil;
import dieci.hibernate.HibPrice;
import dieci.hibernate.HibProduct;
import dieci.system.Price;
import dieci.system.Product;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.hibernate.Session;
import java.util.logging.Logger;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

public class ProductHibernateDAO implements ProductDAO
{

    private static Logger logger = Logger.getLogger("ProductDAO.log");

    
    @Override
    public List<Product> list()
    {
        List<Product> products = new ArrayList<>();

        Session session = SessionFactoryUtil.getInstance().getCurrentSession();
        try {
            session.beginTransaction();

            List<HibProduct> hibProducts = session.createCriteria(HibProduct.class).
                    add(Restrictions.eq("deleted", 0)).addOrder(Order.asc("productDescription")).list();
            for (HibProduct dbProd : hibProducts) {
                Set<Price> prices = new HashSet<>();
                for (HibPrice hibPrice : dbProd.getProductPrice()) {
                    prices.add(new Price(hibPrice.getPrice(), hibPrice.getId().getPriceDate()));
                }
                Product prod = new Product(dbProd.getProductCode(), dbProd.getProductDescription(),
                        dbProd.getProductDescriptionLong(), prices, dbProd.getProductSize(), 
                        dbProd.getProductColor(),dbProd.getCost(), dbProd.getDeleted());
                prod.setProductId(dbProd.getProductId());
                products.add(prod);
            }

            return products;
        }
        catch (Exception e) {

            logger.log(Level.INFO, "Error listando productos", e.getMessage());

            throw new IllegalStateException("Error al listar",e);
        }
        finally {
            if (session!=null && session.isOpen()) {

                session.close();
            }
        }
    }
    

    @Override
    public List<Product> findByProductName(String name)
    {
        List<Product> result = new ArrayList<>();
        Session session = SessionFactoryUtil.getInstance().getCurrentSession();
        try {
            session.beginTransaction();

            List<HibProduct> hibProducts = session.createCriteria(HibProduct.class).
                    add(Restrictions.eq("deleted", 0)).add(Restrictions.like("productDescription", name+"%")).list();
            
            if (hibProducts != null) {
                for (HibProduct hibProduct : hibProducts)
                {
                    Product productFound;
                    
                    Set<Price> prices = new HashSet<>();
                    for (HibPrice price : hibProduct.getProductPrice()) 
                    {
                        Price p = new Price(price.getPrice(), price.getId().getPriceDate());
                        p.setProductId(price.getId().getProductId());
                        prices.add(p);
                    }
                    productFound = new Product(hibProduct.getProductCode(),
                            hibProduct.getProductDescription(),
                            hibProduct.getProductDescriptionLong(),
                            prices, hibProduct.getProductSize(), hibProduct.getProductColor(),
                            hibProduct.getCost(), hibProduct.getDeleted());
                    productFound.setProductId(hibProduct.getProductId());
                    
                    result.add(productFound);
                }

            }

        }
        catch (Exception e) {
            throw new IllegalStateException("Error al buscar por articulo",e);
        }
        finally {
            if (session!=null && session.isOpen()) {

                session.close();
            }
        }

        return result;
    }

    @Override
    public Product findByProductCode(String code)
    {
        Product result = null;
        Session session = SessionFactoryUtil.getInstance().getCurrentSession();
        try {
            session.beginTransaction();

            HibProduct hibProduct = (HibProduct) session.createCriteria(HibProduct.class).
                    add(Restrictions.eq("deleted", 0)).add(Restrictions.eq("productCode", code)).uniqueResult();
            if (hibProduct != null) {
                Set<Price> prices = new HashSet<>();
                for (HibPrice price : hibProduct.getProductPrice()) {

                    Price p = new Price(price.getPrice(), price.getId().getPriceDate());
                    p.setProductId(price.getId().getProductId());
                    prices.add(p);
                }
                result = new Product(hibProduct.getProductCode(),
                        hibProduct.getProductDescription(),
                        hibProduct.getProductDescriptionLong(),
                        prices, hibProduct.getProductSize(), hibProduct.getProductColor(),
                        hibProduct.getCost(), hibProduct.getDeleted());
                result.setProductId(hibProduct.getProductId());
            }

        }
        catch (Exception e) {
            throw new IllegalStateException("Error al buscar por articulo",e);
        }
        finally {
            if (session!=null && session.isOpen()) {

                session.close();
            }
        }

        return result;
    }


    @Override
    public void delete(PersistentObject object)
    {
        Session session = null;

        Product prod = (Product) object;
        Product found = findByProductCode(prod.getProductCode());
        try {
            session = SessionFactoryUtil.getInstance().getCurrentSession();
            
            session.beginTransaction();

            if (found != null) 
            {
                //UPDATE ELIMINADO COLUMN WITH 1
                prod.setProductId(found.getProductId());
                prod.setDeleted(1);                
                HibProduct hibProduct = new HibProduct(prod.getProductId(), (Product) prod);
                session.saveOrUpdate(hibProduct);

            }
            
            session.getTransaction().commit();

        }
        catch (Exception e) {
            if(session!=null){
                session.getTransaction().rollback();
            }            
            throw new IllegalStateException("Error al eliminar",e);
        }
        finally {
            if (session!=null && session.isOpen()) {

                session.close();
            }
        }
    }

    @Override
    public void saveOrUpdate(PersistentObject object)
    {
        Session session = null;

        Product prod = (Product) object;
        Product found = findByProductCode(prod.getProductCode());
        try {
            session = SessionFactoryUtil.getInstance().getCurrentSession();
            
            session.beginTransaction();

            if (found != null) 
            {
                //UPDATE
                prod.setProductId(found.getProductId());

                Set<HibPrice> hibPrices = new HashSet<>();
                for (Price price : prod.getProductPrice()) {
                    HibPrice p = new HibPrice(price, prod.getProductId());
                    hibPrices.add(p);
                }
                HibProduct hibProduct = new HibProduct(prod.getProductId(), (Product) prod);
                hibProduct.setProductPrice(hibPrices);
                session.saveOrUpdate(hibProduct);

            }
            else 
            {
                //NEW
                HibProduct hibProduct = new HibProduct(prod);

                // generate new id for the product
                session.save(hibProduct);
                // add the prices
                for (Price price : prod.getProductPrice()) {
                    hibProduct.getProductPrice().add(
                            new HibPrice(price, hibProduct.getProductId()));
                }

                // If the enty already exist update it.
                session.saveOrUpdate(hibProduct);
            }

            session.getTransaction().commit();

        }
        catch (Exception e) {
            if(session!=null){
                session.getTransaction().rollback();
            }            
            throw new IllegalStateException("Error al guardar o actualizar",e);
        }
        finally {
            if (session!=null && session.isOpen()) {

                session.close();
            }
        }
    }

    @Override
    public Product findById(long id)
    {
        Product result = null;
        Session session = SessionFactoryUtil.getInstance().getCurrentSession();
        try {
            session.beginTransaction();

            HibProduct hibProduct = (HibProduct) session.createCriteria(HibProduct.class).
                    add(Restrictions.eq("deleted", 0)).add(Restrictions.eq("productId", id)).uniqueResult();
            if (hibProduct != null) {
                Set<Price> prices = new HashSet<>();
                for (HibPrice price : hibProduct.getProductPrice()) {

                    Price p = new Price(price.getPrice(), price.getId().getPriceDate());
                    p.setProductId(price.getId().getProductId());
                    prices.add(p);
                }
                result = new Product(hibProduct.getProductCode(),
                        hibProduct.getProductDescription(),
                        hibProduct.getProductDescriptionLong(),
                        prices, hibProduct.getProductSize(), hibProduct.getProductColor(),
                        hibProduct.getCost(), hibProduct.getDeleted());
                result.setProductId(hibProduct.getProductId());
            }

        }
        catch (Exception e) {
            throw new IllegalStateException("Error al buscar por id",e);
        }
        finally {
            if (session!=null && session.isOpen()) {

                session.close();
            }
        }

        return result;
    }
    
    public void saveOrUpdateList(List<Product> products) 
    {
        Session session = null;

        try 
        {
            session = SessionFactoryUtil.getInstance().getCurrentSession();

            session.beginTransaction();
                
            for (PersistentObject object :  products) 
            {
                Product prod = (Product) object;
                Product found = findByProductCode(prod.getProductCode());
                
                if (found != null) {
                    //UPDATE
                    prod.setProductId(found.getProductId());

                    Set<HibPrice> hibPrices = new HashSet<>();
                    for (Price price : prod.getProductPrice()) {
                        HibPrice p = new HibPrice(price, prod.getProductId());
                        hibPrices.add(p);
                    }
                    HibProduct hibProduct = new HibProduct(prod.getProductId(), (Product) prod);
                    hibProduct.setProductPrice(hibPrices);
                    session.saveOrUpdate(hibProduct);

                } else {
                    //NEW
                    HibProduct hibProduct = new HibProduct(prod);

                    // generate new id for the product
                    session.save(hibProduct);
                    // add the prices
                    for (Price price : prod.getProductPrice()) {
                        hibProduct.getProductPrice().add(
                                new HibPrice(price, hibProduct.getProductId()));
                    }

                    // If the enty already exist update it.
                    session.saveOrUpdate(hibProduct);
                }
            }
            
            session.getTransaction().commit();
            

        } 
        catch (Exception e) 
        {
            if (session != null) 
            {
                session.getTransaction().rollback();
            }
            throw new IllegalStateException("Error al guardar o actualizar", e);
        } 
        finally 
        {
            if (session != null && session.isOpen()) 
            {

                session.close();
            }
        }
    }
}
